<?php

const OPENSSL_KEY = 'AdhereToTBl';
const OPENSSL_IV = 'aBoXxLgt47t546tt';
const ACCESS_CONTROL_ALLOW_HEADERS = 'X-Requested-With, Content-Type, Accept, Origin, Authorization, Token, AuthorizationWechat';
const ACCESS_CONTROL_ALLOW_METHODS = 'GET, POST, PUT, DELETE, PATCH, OPTIONS';

const DEFAULT_SORT = 1000;

/**
 * 解密字符串
 * @param string $data
 * @param string|null $key
 * @param string|null $iv
 * @return string|false
 */
function decryptOpenssl(string $data, string|null $key = null, string|null $iv = null): string|false
{
        $key = $key ?: OPENSSL_KEY;
        $iv = $iv ?: OPENSSL_IV;
        return openssl_decrypt(urldecode(base64_decode($data)), "AES-128-CBC", $key, OPENSSL_RAW_DATA, $iv);
}

/**
 * 加密字符串
 * @param string $data
 * @param string|null $key
 * @param string|null $iv
 * @return string
 */
function encryptOpenssl(string $data, string|null $key = null, string|null $iv = null): string
{
        $key = $key ?: OPENSSL_KEY;
        $iv = $iv ?: OPENSSL_IV;
        return str_replace('=', '', base64_encode(urlencode(openssl_encrypt($data, "AES-128-CBC", $key, OPENSSL_RAW_DATA, $iv))));
}

/**
 * 数组模糊搜索
 * @param array $targetArray
 * @param array $searchArray
 * @return array
 */
function arrayBlurSearch(array $targetArray, array $searchArray): array
{
        $arrReturn = [];
        foreach ($searchArray as $v) {
                foreach ($targetArray as $k2 => $v2) {
                        if (str_contains($v2, $v)) {
                                if (is_numeric($k2)) {
                                        $arrReturn[] = $v2;
                                } else {
                                        $arrReturn[$k2] = $v2;
                                }
                        }
                }
        }
        return $arrReturn;
}

/**
 * 数组键名模糊搜索
 * @param array $targetArray
 * @param array $searchKey
 * @return array
 */
function arrayKeyBlurSearch(array $targetArray, array $searchKey): array
{
        $arrKey = array_keys($targetArray);
        $arrValue = array_values($targetArray);
        $arrReturn = [];
        foreach ($arrKey as $k => $v) {
                foreach ($searchKey as $v2) {
                        if (str_contains($v2, $v)) {
                                $arrReturn[$v2] = $arrValue[$k];
                        }
                }
        }
        return $arrReturn;
}

/**
 * 常量枚举转索引数组
 * @param array $cases
 * @param string $labelName
 * @param string $valueName
 * @return array
 */
function constantsEnumToIndexArray(array $cases, string $labelName = 'label', string $valueName = 'value'): array
{
        return array_map(function ($v) use ($labelName, $valueName) {
                return [$labelName => $v->getMessage(), $valueName => $v->value];
        }, $cases);
}

/**
 * 常量枚举转关联数组
 * @param array $cases
 * @return array
 */
function constantsEnumToKeyArray(array $cases): array
{
        $arrResult = [];
        foreach ($cases as $v) {
                $arrResult[$v->value] = $v->getMessage();
        }
        return $arrResult;
}

/**
 * 获取雪花id
 * @param bool $toString
 * @return mixed
 * @throws Exception
 */
function snowflakeId(bool $toString = true): mixed
{
        try {
                $container = \Hyperf\Context\ApplicationContext::getContainer();
                $generator = $container->get(\Hyperf\Snowflake\IdGeneratorInterface::class);
                $id = $generator->generate();
                return $toString ? strval($id) : $id;
        } catch (Throwable $t) {
                throw new Exception('分布式雪花ID：' . $t->getMessage());
        }
}

/**
 * 自定义加解密
 * @param string $data
 * @param int $type 1加密 2解密
 * @param string|null $key
 * @param int $expire
 * @param int $length 随机密钥长度 取值 0-32;
 * @return string
 */
function customizeEncryptDecrypt(string $data, int $type, string|null $key = null, int $expire = 0, int $length = 4): string
{
        // 随机密钥长度 取值 0-32;
        // 加入随机密钥，可以令密文无任何规律，即便是原文和密钥完全相同，加密结果也会每次不同，增大破解难度。
        // 取值越大，密文变动规律越大，密文变化 = 16 的 $intLength 次方
        // 当此值为 0 时，则不产生随机密钥
        $strKey = md5($key ?: OPENSSL_KEY);
        $strKeyA = md5(substr($strKey, 0, 16));
        $strKeyB = md5(substr($strKey, 16, 16));
        $strKeyC = '';
        if ($length > 0) {
                if ($type === 1) {
                        $strKeyC = substr(md5(microtime()), -$length);
                } else {
                        $strKeyC = substr($data, 0, $length);
                }
        }
        $strCryptKey = $strKeyA . md5($strKeyA . $strKeyC);
        $intCryptKeyLength = strlen($strCryptKey);
        if ($type === 1) {
                $expire = $expire ? ($expire + time()) : 0;
                $data = sprintf('%010d', $expire) . substr(md5($data . $strKeyB), 0, 16) . $data;
        } else {
                $data = urldecode(base64_decode(substr($data, $length)));
        }
        $intDataLength = strlen($data);
        $result = '';
        $arrBox = range(0, 255);
        $arrRandomKey = [];
        for ($i = 0; $i <= 255; $i++) {
                $arrRandomKey[$i] = ord($strCryptKey[$i % $intCryptKeyLength]);
        }
        for ($j = $i = 0; $i < 256; $i++) {
                $j = ($j + $arrBox[$i] + $arrRandomKey[$i]) % 256;
                $tmp = $arrBox[$i];
                $arrBox[$i] = $arrBox[$j];
                $arrBox[$j] = $tmp;
        }
        for ($a = $j = $i = 0; $i < $intDataLength; $i++) {
                $a = ($a + 1) % 256;
                $j = ($j + $arrBox[$a]) % 256;
                $tmp = $arrBox[$a];
                $arrBox[$a] = $arrBox[$j];
                $arrBox[$j] = $tmp;
                $result .= chr(ord($data[$i]) ^ ($arrBox[($arrBox[$a] + $arrBox[$j]) % 256]));
        }
        if ($type === 2) {
                $intSubResult1 = intval(substr($result, 0, 10));
                $strSubResult2 = substr($result, 10, 16);
                $strSubResult3 = substr(md5(substr($result, 26) . $strKeyB), 0, 16);
                if (
                        (($intSubResult1 === 0) || (($intSubResult1 - time()) > 0)) &&
                        ($strSubResult2 == $strSubResult3)
                ) {
                        return substr($result, 26);
                } else {
                        return '';
                }
        } else {
                return $strKeyC . str_replace('=', '', base64_encode(urlencode($result)));
        }
}


/**
 * 业务成功返回
 * @param mixed|null $data
 * @param mixed|null $msg
 * @return int[]
 */
function businessSuccess(mixed $data = null, mixed $msg = null): array
{
        $arrResult = ['code' => \App\Constants\Common\ApiStatusEnum::SUCCESS->value];
        $arrResult['msg'] = $msg ?: trans('common.operateSuccess');
        if ($data !== null) $arrResult['data'] = $data;
        return $arrResult;
}

/**
 * 业务错误返回
 * @param mixed|null $msg
 * @param int|null $code
 * @return int[]
 */
function businessError(mixed $msg = null, int|null $code = null): array
{
        if ($code === null) $code = \App\Constants\Common\ApiStatusEnum::ERROR->value;
        $arrResult = ['code' => $code];
        $arrResult['msg'] = $msg ?: trans('common.operateFailed');
        return $arrResult;
}

if (!function_exists('__')) {
        function __(string $key, array $replace = [], ?string $locale = null)
        {
                return \Hyperf\Translation\__($key, $replace, $locale);
        }
}

if (!function_exists('trans')) {
        function trans(string $key, array $replace = [], ?string $locale = null)
        {
                return \Hyperf\Translation\__($key, $replace, $locale);
        }
}

if (!function_exists('trans_choice')) {
        function trans_choice(string $key, $number, array $replace = [], ?string $locale = null): string
        {
                return \Hyperf\Translation\trans_choice($key, $number, $replace, $locale);
        }
}